/*
*   Matt Goranson
*   Senior Design 1, Project 2
*   Visual Indication, Chaos Cube
*   Protoyping -> Final Project
*
*   The purpose of this software is to alert the user of a power-up,
*   failed roll, and the 6 possible rolls.
*/

#include <msp430g2553.h>
#include "ChaosCube.h"

int transmit_percent(int, int, int);
int transmit(int[]);
int send_bit(int);
void set_outputs_on(void);
void set_outputs(unsigned int red, unsigned int green, unsigned int blue);
static inline void clock_low(void);
static inline void clock_high(void);
static inline void latch_low(void);
static inline void latch_high(void);
static inline void blank_low(void);
static inline void blank_high(void);

void vr_poison(void);
void vr_magic(void);
void vr_shoot(void);
void vr_seduce(void);

extern int VISUAL_RELEASE;


void initVisual(void)
{
   P2DIR |= (P_VISUAL_LAT | P_VISUAL_SCLK | P_VISUAL_SIN | P_VISUAL_BLANK);
   P2DIR &= ~P_VISUAL_SOUT;
   
   P2SEL  &= ~(P_VISUAL_LAT | P_VISUAL_SCLK | P_VISUAL_SIN | P_VISUAL_SOUT | P_VISUAL_BLANK); // set to GPIO configuration.
   P2SEL2 &= ~(P_VISUAL_LAT | P_VISUAL_SCLK | P_VISUAL_SIN | P_VISUAL_SOUT | P_VISUAL_BLANK); // set to GPIO configuration.

   blank_high();
   set_outputs_on();
}

void sendVisual(int face)
{
  int hue;
  int transmit_count = 0;
  blank_low();
  switch (face){
    case failure://failure, solid red
      while(transmit_count < 3000){ // wait for release
        transmit_percent(50,0,0);
        transmit_count++;
      }
      transmit_count = 0;
    break;

    case success://success, solid green
      while(transmit_count < 3000){
        transmit_percent(0,50,0);
        transmit_count++;
      }
      transmit_count = 0;
    break;

    case face1://face1, heartbeat
      while(VISUAL_RELEASE != 1){
        for(hue = 1; hue <= 100; hue++){
          transmit_percent(hue,0,0);
          delay_ms(2);
        }
        transmit_percent(0,0,0);
        for(hue = 1; hue <= 100; hue++){
          transmit_percent(hue,0,0);
          delay_ms(2);
        }
        transmit_percent(0,0,0);
        delay_ms(500);
      }
    break;

    case face2://face2, fast flash green
      vr_poison();
    break;

    case face3://face3, slow flash purple
      vr_seduce();
    break;

    case face4://face4, fast flash blue
      r_magic();
    break;

    case face5://face5, slow flash yellow
      while(VISUAL_RELEASE != 1){
        for(hue = 1; hue <= 100; hue++){
          transmit_percent(hue, hue, 0);
          delay_ms(8);
        }
        for(hue = 100; hue >= 1; hue--){
          transmit_percent(hue, hue, 0);
          delay_ms(8);
        }
      }
    break;

    case face6://face6, fast flash white
      vr_shoot();
    break;
 }
 blank_high();

 VISUAL_RELEASE = 0;
}

int transmit_percent(int r, int g, int b)
{
  int rgb[3] = {0x7F, 0x7F, 0x7F};
  rgb[0] = (rgb[0] * b) / 100;
  rgb[1] = (rgb[1] * g) / 100;
  rgb[2] = (rgb[2] * r) / 100;
   
  return transmit(rgb);
}

void set_outputs(unsigned int red, unsigned int green, unsigned int blue)
{
  int i;
	
  clock_low();
  send_bit(0);

  for(i = 0; i < 6; i++){
    send_bit(0);
  }

  for(i = 0; i < 6; i++){
    send_bit((red   >> i)&0x1);
    send_bit((green >> i)&0x1);
    send_bit((blue  >> i)&0x1);
  }

  clock_low();
  latch_high();
  latch_low();
  blank_low();
}


void set_outputs_on()
{
  set_outputs(0x3F,0x3F,0x3F);
}

int transmit(int rgb[])
{
  const int data = 0;
  int i = 0;
  int color;
  int bit;
   
  clock_low();
  send_bit(1); // brightness (MSB) of shift data
   
  // 3 bit group for LED detection stuff
  for(i = 0; i < 3; i++){
    send_bit(1);
  }
   
  for(color = 0; color < 3; color++){
    for(bit = 6; bit >= 0; bit--) {
      send_bit((rgb[color] >> bit) & 0x01);
    }
  }
   
  clock_low();
  latch_high();
  latch_low();

  return data;
}

int send_bit(int bit)
{
  int bit_in;
	
  clock_low();
  if (bit)
    P2OUT |= P_VISUAL_SIN;
  else
    P2OUT &= ~P_VISUAL_SIN;

  clock_high();
   	
  bit_in = (P2IN & P_VISUAL_SOUT) ? 0x1 : 0x0;
  return bit_in;
}

static inline void clock_low(void)
{
  P2OUT &= ~P_VISUAL_SCLK;
}

static inline void clock_high(void)
{
  P2OUT |= P_VISUAL_SCLK;
}

static inline void latch_low(void)
{
  P2OUT &= ~P_VISUAL_LAT;
}

static inline void latch_high(void)
{
  P2OUT |= P_VISUAL_LAT;
}

static inline void blank_low(void)
{
  P2OUT &= ~P_VISUAL_BLANK;
}

static inline void blank_high(void)
{
  P2OUT |= P_VISUAL_BLANK;
}

void vr_shoot(void)
{
   int foo = 0;

   while(VISUAL_RELEASE != 1){
      transmit_percent(50, 50, 50);
      delay_ms(50);

      if((foo % 6) == 0)
         set_outputs(0x20, 0, 0);
      else if((foo % 6) == 1)
         set_outputs(0, 0x10, 0);
      else if((foo % 6) == 2)
         set_outputs(0, 0, 0x08);
      else if((foo % 6) == 3)
         set_outputs(0x04, 0, 0);
      else if((foo % 6) == 4)
         set_outputs(0, 0x02, 0);
      else if((foo % 6) == 5)
         set_outputs(0, 0, 0x01);
      foo++;
   }
}

//magic scenario test, blue and yellow
void vr_magic(void)
{
   int foo = 0;

   while(VISUAL_RELEASE != 1){
      transmit_percent(20, 10, 50);
      delay_ms(100);

      if((foo % 6) == 0)
         set_outputs(0x20, 0x1F, 0x1F);
      else if((foo % 6) == 1)
         set_outputs(0x10, 0x2F, 0x2F);
      else if((foo % 6) == 2)
         set_outputs(0x08, 0x37, 0x37);
      else if((foo % 6) == 3)
         set_outputs(0x04, 0x3B, 0x3B);
      else if((foo % 6) == 4)
         set_outputs(0x02, 0x3D, 0x3D);
      else if((foo % 6) == 5)
         set_outputs(0x01, 0x3E, 0x3E);
      foo++;
   }
}

//poison scenario test, green and orange
void vr_poison(void)
{
   int foo = 0;

   while(VISUAL_RELEASE != 1){
      transmit_percent(70, 20, 0);
      delay_ms(100);

      if((foo % 6) == 0)
         set_outputs(0, 0x3F, 0x1F);
      else if((foo % 6) == 1)
         set_outputs(0, 0x3F, 0x2F);
      else if((foo % 6) == 2)
         set_outputs(0, 0x3F, 0x37);
      else if((foo % 6) == 3)
         set_outputs(0, 0x3F, 0x3B);
      else if((foo % 6) == 4)
         set_outputs(0, 0x3F, 0x3D);
      else if((foo % 6) == 5)
         set_outputs(0, 0x3F, 0x3E);
      foo++;
   }
}

void vr_seduce(void)
{
  while(VISUAL_RELEASE != 1){
    for(hue = 1; hue <= 100; hue++){
      transmit_percent(66, 0, hue);
      delay_ms(8);
    }
    for(hue = 100; hue >= 1; hue--){
      transmit_percent(66, 0, hue);
      delay_ms(8);
    }
  }
}
